// Package middleware 常用函数模块
package middleware

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"ginmin/configs"
	"math/rand"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type FunMiddleWare struct{}

type Msg struct {
	Code     int                    `json:"code"`
	Msg      string                 `json:"msg"`
	Backdata map[string]interface{} `json:"data"`
}

// IsMobile 判断是否是移动端
func (middleware *FunMiddleWare) IsMobile(userAgent string) bool {
	if len(userAgent) == 0 {
		return false
	}
	userAgent = strings.ToLower(userAgent)
	isMobile := false
	mobileKeywords := []string{"iphone", "ucweb", "mobile", "android", "silk/", "kindle", "blackberry", "opera mini", "opera mobi"}
	for i := 0; i < len(mobileKeywords); i++ {
		if strings.Contains(userAgent, mobileKeywords[i]) {
			isMobile = true
			break
		}
	}
	return isMobile
}

// GetSalt 获取加密字符
func (middleware *FunMiddleWare) GetSalt() string {
	ServerConfig := configs.GetServerConfig()
	return ServerConfig["HashIDSalt"]
}

// GetUnixTime 取时间戳
func (middleware *FunMiddleWare) GetUnixTime() string {
	return strconv.FormatInt(time.Now().Unix(), 10)
}

// TimeToUnix 日期转时间戳
func (middleware *FunMiddleWare) TimeToUnix(str string) int {
	res, _ := time.ParseInLocation("2006-01-02 15:04:05", str, time.Local)
	return ToInt(res.Unix())
}

// UnixToTime 时间戳转日期
func (middleware *FunMiddleWare) UnixToTime(timestamp int) string {
	timeobj := time.Unix(int64(timestamp), 0)
	return timeobj.Format("2006-01-02 15:04:05")
}

// GenerateCode 获取唯一订单号
func (middleware *FunMiddleWare) GenerateCode() string {
	date := GetFormatTime(time.Now())
	r := rand.Intn(10000)
	code := fmt.Sprintf("%s%d%04d", date, GetTimeTick64(), r)
	return code
}

// GetDirectory 获取运行目录
func (middleware *FunMiddleWare) GetDirectory() string {
	pa, _ := os.Getwd()
	return strings.Replace(pa, "\\", "/", -1)
}

// Md5 md5
func (middleware *FunMiddleWare) Md5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}

// SHA256 sha256
func (middleware *FunMiddleWare) SHA256(str string) string {
	message := []byte(str)
	hash := sha256.New()
	hash.Write(message)
	sum := hash.Sum(nil)
	hashCode := hex.EncodeToString(sum)
	return hashCode
}

// TrimHtml 去除html
func (middleware *FunMiddleWare) TrimHtml(src string) string {
	re, _ := regexp.Compile("<[\\S\\s]+?>")
	src = re.ReplaceAllStringFunc(src, strings.ToLower)
	re, _ = regexp.Compile("<style[\\S\\s]+?</style>")
	src = re.ReplaceAllString(src, "")
	re, _ = regexp.Compile("<script[\\S\\s]+?</script>")
	src = re.ReplaceAllString(src, "")
	re, _ = regexp.Compile("<[\\S\\s]+?>")
	src = re.ReplaceAllString(src, "")
	re, _ = regexp.Compile("\\s{2,}")
	src = re.ReplaceAllString(src, "")
	return strings.TrimSpace(src)
}

// Toacii 加密
func (middleware *FunMiddleWare) Toacii(text string) (string, error) {
	AesKey := []byte(middleware.Md5(middleware.GetSalt())[:16])
	encrypted, err := AesEncrypt([]byte(text), AesKey)
	if err != nil {
		return "", err
	}
	String := base64.StdEncoding.EncodeToString(encrypted)
	String = strings.Replace(String, "+", "-", -1)
	String = strings.Replace(String, "/", "_", -1)
	String = strings.Replace(String, "=", "*", -1)
	return String, nil
}

// Tostring 解密
func (middleware *FunMiddleWare) Tostring(text string) (string, error) {
	text = strings.Replace(text, "-", "+", -1)
	text = strings.Replace(text, "_", "/", -1)
	text = strings.Replace(text, "*", "=", -1)

	AesKey := []byte(middleware.Md5(middleware.GetSalt())[:16])
	encrypted, err := base64.StdEncoding.DecodeString(text)
	if err != nil {
		return "", err
	}
	origin, err := AesDecrypt(encrypted, AesKey)
	if err != nil {
		return "", err
	}
	return string(origin), err
}

// GetClientIP 获取客户端ip
func (middleware *FunMiddleWare) GetClientIP(ctx *gin.Context) string {
	ip := ctx.Request.Header.Get("X-Forwarded-For")
	if strings.Contains(ip, "127.0.0.1") || ip == "" {
		ip = ctx.Request.Header.Get("X-real-ip")
	}
	if index := strings.Index(ip, ","); index >= 0 {
		ip = ip[0:index]
	}
	ip = strings.TrimSpace(ip)
	if ip == "" {
		return "127.0.0.1"
	}
	return ip
}

// Stoi string转interface
func (middleware *FunMiddleWare) Stoi(src map[string]string) map[string]interface{} {
	dest := make(map[string]interface{}, len(src))
	for k := range src {
		dest[k] = src[k]
	}
	return dest
}

// Itos interface转string
func (middleware *FunMiddleWare) Itos(src map[string]interface{}) map[string]string {
	dest := make(map[string]string, len(src))
	for k := range src {
		dest[k] = ToString(src[k])
	}
	return dest
}

// StrCut 首尾获取字符串
func (middleware *FunMiddleWare) StrCut(string, strstart, strend string) string {
	va := strings.Split(string, strstart)
	if len(va) <= 1 {
		return ""
	}
	va = strings.Split(va[1], strend)
	if len(va) <= 1 {
		return ""
	}
	return va[0]
}

// Substr 字符串截取
func (middleware *FunMiddleWare) Substr(str string, start, length int) string {
	rs := []rune(str)
	rl := len(rs)
	end := 0
	if start < 0 {
		start = rl - 1 + start
	}
	end = start + length

	if start > end {
		start, end = end, start
	}
	if start < 0 {
		start = 0
	}
	if start > rl {
		start = rl
	}
	if end < 0 {
		end = 0
	}
	if end > rl {
		end = rl
	}
	return string(rs[start:end])
}

// ContainsMultipleChars 判断是否包含多个字符串
func (middleware *FunMiddleWare) ContainsMultipleChars(str string, chars []string) bool {
	found := false
	for _, c := range chars {
		if str == c {
			found = true
			break
		}
	}
	if !found {
		return false
	}
	return true
}

// Replaces 批量替换
func (middleware *FunMiddleWare) Replaces(str string, arr []string, str1 string) string {
	for _, char := range arr {
		newStr := strings.Replace(str, char, str1, -1)
		str = newStr
	}
	return str
}

// 支持函数
func GetTimeTick64() int64 {
	return time.Now().UnixNano() / 1e6
}
func GetTimeTick32() int32 {
	return int32(time.Now().Unix())
}
func GetFormatTime(time time.Time) string {
	return time.Format("20060102")
}
func AesEncrypt(origData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	origData = PKCS7Padding(origData, blockSize)
	iv := []byte("1234567890123456")
	blockMode := cipher.NewCBCEncrypter(block, iv)
	crypted := make([]byte, len(origData))
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}
func AesDecrypt(crypted, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	iv := []byte("1234567890123456")
	blockMode := cipher.NewCBCDecrypter(block, iv)
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)
	origData = pKCS7UnPadding(origData)
	return origData, nil
}
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}
func pKCS7UnPadding(origData []byte) []byte {
	length := len(origData)
	if length == 0 {
		return []byte{}
	}
	unpadding := int(origData[length-1])
	if unpadding > length {
		return []byte("")
	}
	return origData[:(length - unpadding)]
}
